#pragma once
#ifndef LIT_STANDALONE
#ifndef __LIT__MODULE__HH__
#define __LIT__MODULE__HH__

#include <OgrePlatform.h>
#include <OgreDynLib.h>
#include <OgreDynLibManager.h>
#include "LitExceptions.h"
#include "LitItemManager.hpp"
#include "LitPointer.hpp"
#include <Windows.h>
#include "LitSingleton.hpp"
#include "LitLibraryManager.h"

namespace Lit
{
	enum ModuleType
	{
		MT_GAME,
		MT_FILE_FORMAT,
		MT_CORE
	};

	class Module
	{
		bool			mLoaded;
		LibraryPtr		mHandle;
		String			mName;
	public:
		Module( const String &name );
		virtual ~Module();
		
		virtual void create();
		virtual void destroy();

		const String& getName() const;
		
		void setHandle( LibraryPtr lib );
		LibraryPtr handle() const;

	};
	typedef RefPtr<Module> ModulePtr;
	class ModuleManager
	{
	public:
		typedef std::vector<ModulePtr> vec_t;
		typedef vec_t::iterator itor;
		typedef vec_t::const_iterator const_itor;

		typedef Module* (*CreatorPrototype)();
		typedef void (*DestructorPrototype)(Module*);

	protected:
		vec_t mMods;

	public:
		ModuleManager(){}
		~ModuleManager( ){ clear(); }

		void clear(){
			while( mMods.empty() )
			{
				itor i=mMods.begin();
				destroyModule( i );
			}
			mMods.clear();
		}
		
		itor find(const String &name){
			for( itor i=mMods.begin(); i!=mMods.end(); i++ )
				if( (*i)->getName() == name )
					return i;
			return mMods.end();
		}
		const_itor find(const String &name) const{
			for( const_itor i=mMods.cbegin(); i!=mMods.cend(); i++ )
				if( (*i)->getName() == name )
					return i;
			return mMods.cend();
		}
		bool hasModule( const String &name ) const{
			return find(name) != mMods.end();
		}
		virtual ModulePtr createModule( const String &library_name )
		{
			if( hasModule(library_name) ) return (*find(library_name));
			LibraryPtr lib( LibraryManager::Instance().load(library_name) );
			ModulePtr m((*lib->resolve<CreatorPrototype>("create_plugin"))());
			m->setHandle( lib );
			mMods.push_back(m);
			return m;
		}
		virtual void destroyModule( itor i )
		{
			if( i==mMods.end() )
				return;
			LibraryPtr lib( (*i)->handle() );
			(*lib->resolve<DestructorPrototype>("destroy_plugin"))(*(*i));
			mMods.erase( i );
		}
	};
};

#endif
#endif